package com.lry.config;

import lombok.var;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {

    @Bean
    public ReactiveUserDetailsService userDetailsService(){
        UserDetails admin = User.withDefaultPasswordEncoder()
                .username("admin")
                .password("admin")
                .roles("ADMIN")
                .build();

        UserDetails guest = User.withDefaultPasswordEncoder()
                .username("guest")
                .password("guest")
                .roles("guest")
                .build();

        return new MapReactiveUserDetailsService(admin,guest);
    }

    //PUT，POST，DELETE归属admin，游客只能访问get
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http){
        return http.authorizeExchange()
                .pathMatchers(HttpMethod.PUT,"/product/**")
                .hasAnyRole("ADMIN")
                .pathMatchers(HttpMethod.POST,"/product/**")
                .hasAnyRole("ADMIN")
                .pathMatchers(HttpMethod.DELETE,"/product/**")
                .hasAnyRole("ADMIN")
                .pathMatchers("/product/**")

                .authenticated()
                .pathMatchers("/product/**").

                        access((mono,obj)->mono.map(auth->{
                            HttpMethod httpMethod = obj.getExchange().getRequest().getMethod();
                            boolean granted = false;
                            if (httpMethod == HttpMethod.PUT
                                    || httpMethod == HttpMethod.POST
                                    || httpMethod == HttpMethod.DELETE) {
                                granted = auth.getAuthorities()
                                        .stream()
                                        .map(GrantedAuthority::getAuthority)
                                        .anyMatch("ROLE_ADMIN"::equals);
                            }else{
                                granted = auth.isAuthenticated();
                            }
                            return new AuthorizationDecision(granted);
                        }).switchIfEmpty(Mono.justOrEmpty(new AuthorizationDecision(false)))
                        ).anyExchange()
                        .permitAll()
                .and().httpBasic().and().csrf().disable().build();
    }

}
